/**
 * 组件箱
 * 用途:方便在复杂的组件中快速相互通讯
 * 详细说明见./readme.md
 */
import Vue from 'vue';

export class T_compBox {
  // 事件GUID
  private _emitGUID: string;

  // 组件箱
  private compMap = new Map();

  constructor(GUID: string) {
    // 最终应用组件统一用此GUID 可参考开发模块devModal主index.vue写法
    this._emitGUID = GUID;
  }

  // 以下划线分格合并字串
  private mergeName(compID: string, name: string, funName?: string): string {
    return funName ? `${compID}_${funName}_${name}` : `${compID}_${name}`;
  }

  // 注入组件引用
  public addComp(name: string, comp: any) {
    this.compMap.set(name, comp);
  }

  // 批量注入组件引用
  public addComps(objs: Array<{ name: string; comp: any }>) {
    objs.forEach(obj => this.compMap.set(obj.name, obj.comp));
  }

  // 注入组件引用将 compID+_+funName?+_+name合并为组件key
  public addCompMergeName(
    compID: string,
    name: string,
    comp: any,
    funName?: string
  ) {
    this.compMap.set(this.mergeName(compID, name, funName), comp);
  }

  // 批量注入组件引用将 compID+_+funName?+_+name合并为组件key
  public addCompsMergeName(
    compID: string,
    objs: Array<{ name: string; comp: any }>,
    funName?: string
  ) {
    objs.forEach(obj =>
      this.compMap.set(this.mergeName(compID, obj.name, funName), obj.comp)
    );
  }

  // 删除组件箱对象引用
  public removeComp(name: string) {
    this.compMap.delete(name);
  }

  // 批量删除组件箱对象引用
  public removeComps(names: Array<string>) {
    names.forEach(n => this.compMap.delete(n));
  }

  // 删除组件箱对象引用 将compID+_+funName?+_+name合并为组件key
  public removeCompMergeName(
    compID: string,
    name: string,
    funName?: string
  ): void {
    this.compMap.delete(this.mergeName(compID, name, funName));
  }

  // 批量删除组件箱对象引用 将compID+_+funName?+_+name合并为组件key
  public removeCompsMergeName(
    compID: string,
    names: Array<string>,
    funName?: string
  ): void {
    names.forEach(n => this.compMap.delete(this.mergeName(compID, n, funName)));
  }

  // 删除以ID开头的引用
  public removeCompsWithCompID(compID: string): void {
    const exp = new RegExp(`^${compID}`);
    for (const k in this.compMap) {
      exp.test(k) && this.compMap.delete(k);
    }
  }

  //  获取组件箱中对象实例
  public getComp(name: string): any {
    return this.compMap.get(name);
  }

  //  批量获取组件箱中对象实例
  public getComps(names: Array<string>): Array<{ name: string; comp: any }> {
    const obj: Array<{ name: string; comp: any }> = [];
    names.forEach(n => {
      const o: any = this.getComp(n);
      if (o) obj.push({ name: n, comp: o });
    });
    return obj;
  }

  //  获取组件箱中对象实例 将compID+_+funName?+_+name合并为组件key
  public getCompMergeName(compID: string, name: string, funName?: string): any {
    return this.compMap.get(this.mergeName(compID, name, funName));
  }

  //  批量获取组件箱中对象实例 将compID+_+funName?+_+name合并为组件key 返回name是传入names的值非compBox key
  public getCompsMergeName(
    compID: string,
    names: Array<string>,
    funName?: string
  ): Array<{ name: string; comp: any }> {
    const obj: Array<{ name: string; comp: any }> = [];
    names.forEach(n => {
      const o: any = this.getCompMergeName(compID, n, funName);
      if (o) obj.push({ name: n, comp: o });
    });
    return obj;
  }

  //  通过正则表达式匹配注册名返回实例
  public getCompsRegexMathName(
    regEx: string
  ): Array<{ name: string; comp: any }> {
    const regExp = new RegExp(regEx);
    const obj: Array<{ name: string; comp: any }> = [];
    this.compMap.forEach((v, k) => {
      if (regExp.test(k)) {
        obj.push({ name: k, comp: v });
      }
    });

    return obj;
  }

  // 获取组件ID
  public get emitGUID(): string {
    return this._emitGUID;
  }

  // 外部应用间统一ID
  public getDefGUID(): string {
    // 最终应用组件统一用此GUID 可参考开发模块devModal主index.vue写法
    return this._emitGUID;
  }

  /**
   * description: 将本类实例通过事件广播
   * emitGUID:可指定发送事件名，注意事件名的唯一性。
   */
  public broadcast(emitGUID?: string) {
    Vue.$bus.$emit(emitGUID || this._emitGUID, this);
  }

  public findCompByFunName(funName: string): any {
    for (const [k, v] of this.compMap) {
      if (v?.funName && v.funName === funName) {
        return v;
      }
    }
    return null;
  }
}

export interface I_compBox extends T_compBox {}

export interface I_compBoxInfo {
  TcompBox: I_compBox;
  compID: string;
}
